package com.kfm.kfmchat.controller;


import com.kfm.kfmchat.listener.ChatGPTEventSourceListener;
import com.kfm.kfmchat.listener.ChatStreamEventSourceListener;
import com.kfm.kfmchat.service.ChatService;
import com.kfm.shop.domain.Chat;
import com.unfbx.chatgpt.OpenAiStreamClient;
import com.unfbx.chatgpt.entity.chat.ChatCompletion;
import com.unfbx.chatgpt.entity.chat.Message;
import com.unfbx.chatgpt.interceptor.OpenAILogger;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/chat")
public class ChatGPTController {

    @Resource
    private ChatService chatService;

    @RequestMapping("/stream/{question}")
    public SseEmitter stream(@PathVariable("question") String question, HttpServletRequest request) {
        return ask(question, request);
    }

    @RequestMapping("/stream2/{question}")
    public SseEmitter ask1(@PathVariable("question") String question, HttpServletRequest request) {
        return ask(question, request);
    }

    @RequestMapping("/getHistory")
    public List<Chat> getHistory(HttpServletRequest request) {
        String ip = "0:0:0:0:0:0:0:1".equals(request.getRemoteAddr()) ? "127.0.0.1" : request.getRemoteAddr();
        return chatService.selectByIp(ip);
    }


    // 流式响应 openai 给我们返回 的内容是流式的  此时 openai 是服务端 我们现在的 springboot 相当于是客户端 建立了一个 EventSource
    // 服务端一直在给客户端相应内容 监听  EventSource 的变化情况
    // 客户端 持续去接受这个内容 监听  EventSource 的变化情况
    // EventSourceListener 是一个 监听 EventSource 变化情况的抽象类
    // onOpen onClosed onEvent(变化的内容) onError 对应 EventSource 的四种变化情况
    // 将收到的数据 发送给 前端 SseEmitter 持续发送内容
    // springboot 又是一个服务端 向 客户端持续发送响应内容  建立一个 EventSource 服务端通过 SseEmitter 持续发送内容
    // 客户端 持续去接受这个内容 监听  EventSource 的变化情况
    // EventSource 监听他的改变 onopen onmessage(变化) onerror onclose
    private SseEmitter ask(String question, HttpServletRequest request) {
        // Htt
        //         Pro
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger());
        OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .addInterceptor(httpLoggingInterceptor)// 自定义日志
                .connectTimeout(30, TimeUnit.SECONDS)// 自定义超时时间
                .writeTimeout(30, TimeUnit.SECONDS)// 自定义超时时间
                .readTimeout(30, TimeUnit.SECONDS)// 自定义超时时间
                .build();
        OpenAiStreamClient client = OpenAiStreamClient.builder()
                .apiHost("https://ycdl.ysywy.shop/") // 设置的是代理服务器的地址
                .okHttpClient(okHttpClient)
                .apiKey(List.of("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"))
                .build();
        Message message = Message.builder().role(Message.Role.USER).content(question).build();
        ChatCompletion chatCompletion = ChatCompletion.builder().messages(List.of(message)).build();
        // 第二个参数 是监听 EventSource 如何操作  这里的 EventSource 是来自于服务器（openai）响应的内容
        // EventSource
        // 自定义 EventSourceListener --> 将获取的内容（openai响应的内容） 通过 SsEmitter 发送 内容给前端
        // 此时 ChatStreamEventSourceListener 监听的是 本地后端服务 和 openai 服务建立的 EventSource
        ChatStreamEventSourceListener chatStreamEventSourceListener = new ChatStreamEventSourceListener();
        SseEmitter ss = new SseEmitter(0L);
        chatStreamEventSourceListener.setSseEmitter(ss);
        StringBuilder data = new StringBuilder();
        chatStreamEventSourceListener.setAllData(data);
        // ChatGPTEventSourceListener chatGPTEventSourceListener = new ChatGPTEventSourceListener();
        // chatGPTEventSourceListener.setSseEmitter(ss);
        // 当 发送结束 将 响应的完整内容存储到数据
        // 告诉监听器监听的是哪一个 EventSource 监听的是 本地的springboot服务 和 openai之间的 EventSource
        ss.onCompletion(() -> {
            Chat chat = new Chat();
            chat.setQuestion(question);
            chat.setAnswer(data.toString());
            // 0:0:0:0:0:0:0:1 --> 127.0.0.1
            String ip = "0:0:0:0:0:0:0:1".equals(request.getRemoteAddr()) ? "127.0.0.1" : request.getRemoteAddr();
            chat.setIp(ip);
            chatService.insertSelective(chat);
        });
        client.streamChatCompletion(chatCompletion, chatStreamEventSourceListener);
        return ss;
    }
}
